package com.libra.assemble.xutil.email.receive;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.libra.assemble.xutil.Constants;
import com.libra.assemble.xutil.Utils;
import com.libra.assemble.xutil.email.AttachmentForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 解析邮件，取得邮件中的内容.
 * Created by Libra on 15/9/1.
 */
public class AnalyzeMail {

    /**
     * 日志信息
     */
    private static final Logger logger = LoggerFactory.getLogger(AnalyzeMail.class);

    private MimeMessage mimeMessage = null;
    //附件下载后的存放目录
    //private String saveAttachPath = "";
    //存放邮件内容
    //private StringBuffer bodytext = new StringBuffer();


    public AnalyzeMail(MimeMessage mimeMessage) {
        this.mimeMessage = mimeMessage;
    }

    public void setMimeMessage(MimeMessage mimeMessage) {
        this.mimeMessage = mimeMessage;
    }

    /**
     * 获得发件人的姓名[personal]和邮箱地址[address]
     *
     * @return
     * @throws Exception
     */
    public Map<String, String> getFrom() throws Exception {
        Map<String, String> map = Maps.newHashMap();
        InternetAddress[] address = (InternetAddress[]) mimeMessage.getFrom();
        map.put("personal", address[0].getPersonal());
        map.put("address", address[0].getAddress());
        return map;
    }

    /**
     * 获得收件人的姓名[personal]和邮箱地址[address]
     *
     * @return
     * @throws Exception
     */
    public List<Map<String, String>> getMailTo() throws Exception {
        InternetAddress[] addresses = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.TO);
        return readPersonalAndAddress(addresses);
    }

    /**
     * 获得抄送人的姓名[personal]和邮箱地址[address]
     *
     * @return
     * @throws Exception
     */
    public List<Map<String, String>> getMailCc() throws Exception {
        InternetAddress[] addresses = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC);
        return readPersonalAndAddress(addresses);
    }


    /**
     * 获得密送人的姓名[personal]和邮箱地址[address]
     *
     * @return
     * @throws Exception
     */
    public List<Map<String, String>> getMailBcc() throws Exception {
        InternetAddress[] addresses = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC);
        return readPersonalAndAddress(addresses);
    }

    /**
     * 读取姓名[personal]和邮箱地址[address]
     *
     * @param addresses
     * @return
     */
    private List<Map<String, String>> readPersonalAndAddress(InternetAddress[] addresses) {
        List<Map<String, String>> list = Lists.newArrayList();
        Map<String, String> map = Maps.newHashMap();

        //如果没有取得地址信息，则返回空值.
        if (addresses == null) {
            return null;
        }

        for (InternetAddress address : addresses) {
            map.put("personal", address.getPersonal());
            map.put("address", address.getAddress());
            list.add(map);
        }
        return list;
    }


    /**
     * 获得邮件的收件人，抄送，和密送的地址和姓名，根据所传递的参数的不同 "to"----收件人 "cc"---抄送人地址 "bcc"---密送人地址
     */

    /*public String getMailAddress(String type) throws Exception {
        String mailaddr = "";
        String addtype = type.toUpperCase();
        InternetAddress[] address = null;
        if (addtype.equals("TO") || addtype.equals("CC") || addtype.equals("BCC")) {
            if (addtype.equals("TO")) {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.TO);
            } else if (addtype.equals("CC")) {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC);
            } else {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC);
            }
            if (address != null) {
                for (int i = 0; i < address.length; i++) {
                    String email = address[i].getAddress();
                    if (email == null)
                        email = "";
                    else {
                        email = MimeUtility.decodeText(email);
                    }
                    String personal = address[i].getPersonal();
                    if (personal == null)
                        personal = "";
                    else {
                        personal = MimeUtility.decodeText(personal);
                    }
                    String compositeto = personal + "<" + email + ">";
                    mailaddr += "," + compositeto;
                }
                mailaddr = mailaddr.substring(1);
            }
        } else {
            throw new Exception("Error emailaddr type!");
        }
        return mailaddr;
    }*/

    /**
     * 获得邮件主题
     */
    public String getSubject() throws MessagingException {
        String subject = "";
        try {
            subject = MimeUtility.decodeText(mimeMessage.getSubject());
            if (subject == null)
                subject = "";
        } catch (Exception exce) {
        }
        return subject;
    }

    /**
     * 获得邮件发送日期
     */
    public Date getSentDate() throws Exception {
        return mimeMessage.getSentDate();
    }

    /**
     * 获得邮件发送日期
     */
    public String getSentDate(String pattern) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(mimeMessage.getSentDate());
    }

    /**
     * 获得邮件接收日期
     */
    public Date getReceivedDate() throws Exception {
        return mimeMessage.getReceivedDate();
    }

    /**
     * 获得邮件接收日期
     */
    public String getReceivedDate(String pattern) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(mimeMessage.getReceivedDate());
    }

    /**
     * 获得邮件正文内容
     */
    /*
    public String getBodyText() {
        return bodytext.toString();
    }
    */


    /**
     * 解析邮件.
     * 把得到的邮件内容保存到一个StringBuffer对象中.
     * 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析.
     *
     * @param part
     * @throws Exception
     */
    public void analyzeMailContent(StringBuffer bodytext, Part part) throws Exception {
        if (part.isMimeType("text/plain")) {
            logger.info("解析普通文本邮件");
            //普通文本
            bodytext.append((String) part.getContent());
        } else if (part.isMimeType("text/html")) {
            logger.info("解析网页邮件");
            //网页
            bodytext.append((String) part.getContent());
        } else if (part.isMimeType("multipart/*")) {
            logger.info("解析多格式邮件");
            //多格式
            Multipart multipart = (Multipart) part.getContent();

            //递归，全部提取(将多格式拆分为普通文本和网页格式)
            for (int i = 0; i < multipart.getCount(); i++) {
                analyzeMailContent(bodytext, multipart.getBodyPart(i));
            }
        } else if (part.isMimeType("message/rfc822")) {
            logger.info("解析其他格式邮件");
            analyzeMailContent(bodytext, (Part) part.getContent());
        }
    }

    /**
     * 解析邮件.
     * 把得到的邮件内容保存到一个StringBuffer对象中.
     * 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析.
     */
    /*
    public void getMailContent(Part part) throws Exception {
        String contenttype = part.getContentType();
        boolean conname = contenttype.indexOf("name") !=1? false:true ;

        if (part.isMimeType("text/plain") && conname) {
            //普通文本
            bodytext.append((String) part.getContent());
        } else if (part.isMimeType("text/html") && conname) {
            //网页
            bodytext.append((String) part.getContent());
        } else if (part.isMimeType("multipart/*")) {
            //多格式
            Multipart multipart = (Multipart) part.getContent();

            //递归，全部提取
            int counts = multipart.getCount();
            for (int i = 0; i < counts; i++) {
                getMailContent(multipart.getBodyPart(i));
            }
        } else if (part.isMimeType("message/rfc822")) {
            getMailContent((Part) part.getContent());
        }
    }
    */

    /**
     * 判断此邮件是否需要回执，如果需要回执返回"true",否则返回"false"
     */
    public boolean getReplySign() throws MessagingException {
        boolean replysign = false;
        String needreply[] = mimeMessage
                .getHeader("Disposition-Notification-To");
        if (needreply != null) {
            replysign = true;
        }
        return replysign;
    }

    /**
     * 获得此邮件的Message-ID
     */
    public String getMessageId() throws MessagingException {
        return mimeMessage.getMessageID();
    }

    /**
     * 获得此邮件的Content-ID
     */
    public String getContentID() throws MessagingException {
        return mimeMessage.getContentID();
    }

    /**
     * 获得此邮件的Message-Number
     */
    public int getMessageNumber() throws MessagingException {
        return mimeMessage.getMessageNumber();
    }


    /**
     * 【判断此邮件是否未读，如果未读返回返回true,反之返回false】
     * 说明：pop3没有判断邮件是否为已读的功能，要使用Imap才可以.
     *
     * @return
     * @throws MessagingException
     */
    public boolean isUnread() throws MessagingException {
        Flags flags = mimeMessage.getFlags();
        if (flags.contains(Flags.Flag.SEEN)) {
            return false;
        } else {
            return true;

        }
    }

    /**
     * 判断此邮件是否包含附件
     */
    /*public boolean isContainAttach(Part part) throws Exception {
        boolean attachflag = false;
        String contentType = part.getContentType();
        if (part.isMimeType("multipart*//*")) {
            Multipart mp = (Multipart) part.getContent();
            for (int i = 0; i < mp.getCount(); i++) {
                BodyPart mpart = mp.getBodyPart(i);
                String disposition = mpart.getDisposition();
                if ((disposition != null)
                        && ((disposition.equals(Part.ATTACHMENT)) || (disposition
                        .equals(Part.INLINE))))
                    attachflag = true;
                else if (mpart.isMimeType("multipart*//*")) {
                    attachflag = isContainAttach((Part) mpart);
                } else {
                    String contype = mpart.getContentType();
                    if (contype.toLowerCase().indexOf("application") != -1)
                        attachflag = true;
                    if (contype.toLowerCase().indexOf("name") != -1)
                        attachflag = true;
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            attachflag = isContainAttach((Part) part.getContent());
        }
        return attachflag;
    }*/


    /**
     * 取得邮件中附件文件信息.
     *
     * @param list
     * @param part
     * @return
     * @throws Exception
     */
    public void getAttachment(List<AttachmentForm> list, Part part, String path) throws Exception {
        logger.info("ContentType: {}", part.getContentType());
        //contentType主要有三种multipart/mixed(混合的)、multipart/related(有关系的)、multipart/alternative(替代的)
        if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();
            for (int i = 0; i < multipart.getCount(); i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                if (bodyPart.isMimeType("multipart/*")) {
                    //多类型，递归进行解析
                    getAttachment(list, bodyPart, path);
                } else if (bodyPart.getFileName() != null) {
                    String disposition = bodyPart.getDisposition();
                    logger.info("BodyPart Disposition:{}", disposition);
                    String fileName = decodeText(bodyPart.getFileName(), "ISO-8859-1","gb2312");
                    logger.info("文件名：{}", fileName);
                    //保存附件信息
                    Date date = new Date();
                    String diskFileName = date.getTime()+"";
                    if(fileName.lastIndexOf(".") > 0){
                        diskFileName += fileName.substring(fileName.lastIndexOf("."));
                    }
                    AttachmentForm attachmentForm = new AttachmentForm();
                    attachmentForm.setFileName(fileName);
                    attachmentForm.setDiskFileName(diskFileName);
                    attachmentForm.setPhysicsPath(path+diskFileName);
                    attachmentForm.setVisitPath(path+diskFileName);
                    attachmentForm.setFilesize(bodyPart.getSize());
                    attachmentForm.setContentType(decodeText(bodyPart.getContentType(), "ISO-8859-1","gb2312"));
                    attachmentForm.setInputStream(bodyPart.getInputStream());
                    list.add(attachmentForm);

                }


            }

        } else if (part.isMimeType("message/rfc822")) {
            logger.info("MimeType 是 message/rfc822");
//            saveAttachment((Part) part.getContent());
        }
    }


    /**
     * 保存邮件中的附件文件.
     *
     * @param part
     * @throws Exception
     */
    public void saveAttachment(Part part) throws Exception {
        String fileName = "";
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            for (int i = 0; i < mp.getCount(); i++) {
                BodyPart mpart = mp.getBodyPart(i);
                String disposition = mpart.getDisposition();
                if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) || (disposition.equals(Part.INLINE)))) {
                    fileName = mpart.getFileName();
                    if (fileName.toLowerCase().indexOf("gb2312") != -1) {
                        fileName = MimeUtility.decodeText(fileName);
                    }
                    saveFile(fileName, mpart.getInputStream());
                } else if (mpart.isMimeType("multipart/*")) {
                    saveAttachment(mpart);
                } else {
                    fileName = mpart.getFileName();
                    if ((fileName != null)
                            && (fileName.toLowerCase().indexOf("GB2312") != -1)) {
                        fileName = MimeUtility.decodeText(fileName);
                        saveFile(fileName, mpart.getInputStream());
                    }
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            saveAttachment((Part) part.getContent());
        }
    }

    /**
     * 【设置附件存放路径】
     */
    /*public void setAttachPath(String attachpath) {
        this.saveAttachPath = attachpath;
    }
*/

    /**
     * 【获得附件存放路径】
     */
    /*public String getAttachPath() {
        return saveAttachPath;
    }*/

    /**
     * 【真正的保存附件到指定目录里】
     */
    private void saveFile(String fileName, InputStream in) throws Exception {
        String osName = System.getProperty("os.name");

        //文件存放路径
        String storedir = "路径";
        String separator = "";
        if (osName == null)
            osName = "";
        if (osName.toLowerCase().indexOf("win") != -1) {
            separator = "\\";
            if (storedir == null || storedir.equals(""))
                storedir = "d:\\tmp";
        } else {
            separator = "/";
            storedir = "/tmp";
        }
        File storefile = new File(storedir + separator + fileName);
        System.out.println("storefile's path: " + storefile.toString());
        // for(int i=0;storefile.exists();i++){  
        // storefile = new File(storedir+separator+fileName+i);  
        // }  
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(storefile));
            bis = new BufferedInputStream(in);
            int c;
            while ((c = bis.read()) != -1) {
                bos.write(c);
                bos.flush();
            }
        } catch (Exception exception) {
            exception.printStackTrace();
            throw new Exception("文件保存失败!");
        } finally {
            bos.close();
            bis.close();
        }
    }


    /**
     * 更变字符串的字符格式，对字符串进行转码.
     * @param fileName
     * @param oldCharsetName
     * @param newCharsetName
     * @return
     * @throws Exception
     */
    private String decodeText(String fileName, String oldCharsetName, String newCharsetName) throws Exception {
        fileName=new String(fileName.getBytes(oldCharsetName), newCharsetName);
        if(fileName.toLowerCase().indexOf("=?gb")>=0 || fileName.toLowerCase().indexOf("=?utf-8")>=0){
            fileName = decodeText(fileName);
        }
        return fileName;
    }

    /**
     * 递归解码（如果内容/主题中存在编码内容，则递归转码）.
     *
     * @param subject
     * @return
     * @throws Exception
     */
    private String decodeText(String subject) throws Exception {
        String text = null;
        if (subject.toLowerCase().indexOf("=?gb") >= 0) {
            text = subject.substring(subject.toLowerCase().indexOf("=?gb"));
            text = MimeUtility.decodeText(text);
            subject = subject.toLowerCase().substring(0, subject.toLowerCase().indexOf("=?gb")) + text;
        } else if (subject.toLowerCase().indexOf("=?utf-8") >= 0) {
            text = subject.substring(subject.toLowerCase().indexOf("=?utf-8"));
            text = MimeUtility.decodeText(text);
            subject = subject.toLowerCase().substring(0, subject.toLowerCase().indexOf("=?utf-8")) + text;
        }

        if (text != null) {
            while (subject.toLowerCase().indexOf("=?gb") >= 0 || subject.toLowerCase().indexOf("=?utf-8") >= 0) {
                subject = decodeText(subject);
            }
        }
        return subject;
    }



    /**
     * PraseMimeMessage类测试
     */
    public static void main(String args[]) throws Exception {
        Properties props = System.getProperties();
        props.put("mail.smtp.host", "smtp.163.com");
        props.put("mail.smtp.auth", "true");
        Session session = Session.getDefaultInstance(props, null);
        URLName urln = new URLName("pop3", "pop3.163.com", 110, null,
                "rong_1005@163.com", "248858868");
        Store store = session.getStore(urln);
        store.connect();
        Folder folder = store.getFolder("INBOX");
        folder.open(Folder.READ_ONLY);
        Message message[] = folder.getMessages();
        System.out.println("Messages's length: " + message.length);
        AnalyzeMail pmm = null;
        for (int i = 0; i < message.length; i++) {
            System.out.println("======================");
            pmm = new AnalyzeMail((MimeMessage) message[i]);
            System.out.println("Message " + i + " subject: " + pmm.getSubject());
            System.out.println("Message " + i + " sentdate: " + pmm.getSentDate());
            System.out.println("Message " + i + " replysign: " + pmm.getReplySign());
            System.out.println("Message " + i + " hasRead: " + pmm.isUnread());
//            System.out.println("Message " + i + "  containAttachment: " + pmm.isContainAttach((Part) message[i]));
            System.out.println("Message " + i + " form: " + pmm.getFrom());
            System.out.println("Message " + i + " to: " + pmm.getMailTo());
            System.out.println("Message " + i + " cc: " + pmm.getMailCc());
            System.out.println("Message " + i + " bcc: " + pmm.getMailBcc());
            System.out.println("Message " + i + " sentdate: " + pmm.getSentDate());
            System.out.println("Message " + i + " Message-ID: " + pmm.getMessageId());
            // 获得邮件内容===============  
           /* pmm.getMailContent((Part) message[i]);
            System.out.println("Message " + i + " bodycontent: \r\n"
                    + pmm.getBodyText());*/
//            pmm.setAttachPath("D:\\");
//            pmm.saveAttachment((Part) message[i]);
        }
    }
}  